#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN=2000000,INF=0x3f3f3f3f;
int n,m,nn,head[MAXN],d[MAXN],cnt;
bool vis[MAXN];
struct edge
{
	int v,next,val;
}e[MAXN*3];
void addedge(int x,int y,int z)
{
	e[++cnt]=(edge){y,head[x],z};
	head[x]=cnt;
	return;
}
void inedge() 
{
	int x,cnt;
	//横边 
	for(int i=1;i<=m-1;i++)
	{
		scanf("%d",&x);
		addedge(0,i,x);addedge(i,0,x);
	}
	cnt=(m-1)*2;
	for(int i=2;i<n;i++)
	{
		for(int j=1;j<=m-1;j++)
		{
			cnt++;
			scanf("%d",&x);
			addedge(cnt,cnt-m+1,x);addedge(cnt-m+1,cnt,x);
		}
		cnt+=(m-1);
	}
	for(int i=1;i<=m-1;i++)
	{
		scanf("%d",&x);
		addedge(nn,nn-m+i,x);addedge(nn-m+i,nn,x);
	}
	//竖边 
	cnt=m;
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d",&x);
		addedge(cnt,nn,x);addedge(nn,cnt,x);
		for(int j=2;j<m;j++)
		{
			cnt++;
			scanf("%d",&x);
			addedge(cnt,cnt-m,x);addedge(cnt-m,cnt,x);
		}
		scanf("%d",&x);
		addedge(0,cnt-m+1,x);addedge(cnt-m+1,0,x);
		cnt+=m;
	}
	//斜边 
	cnt=0;
	for(int i=1;i<=n-1;i++)
	{
		for(int j=1;j<=m-1;j++)
		{
			cnt++;
			scanf("%d",&x);
			addedge(cnt,cnt+m-1,x);addedge(cnt+m-1,cnt,x);
		}
		cnt+=(m-1);
	}
	return;
}
void SPFA()
{
	queue<int>q;
	q.push(0);
	vis[0]=true;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		vis[u]=false;
		for(int i=head[u];i;i=e[i].next)
		{
			int v=e[i].v;
			if(d[u]+e[i].val<d[v])
			{
				d[v]=d[u]+e[i].val;
				if(!vis[v])
				{
					q.push(v);
					vis[v]=true;
				}
			}
		}
	}
	return;
}
int main()
{
	scanf("%d%d",&n,&m);
	if(n==1)
	{
		int x,ans=INF;
		for(int i=1;i<=m-1;i++)
		{
			scanf("%d",&x);
			ans=min(ans,x);
		}
		printf("%d\n",ans==INF?0:ans);
		return 0;
	}
	else if(m==1)
	{
		int x,ans=INF;
		for(int i=1;i<=n-1;i++)
		{
			scanf("%d",&x);
			ans=min(ans,x);
		}
		printf("%d\n",ans==INF?0:ans);
		return 0;
	}
	nn=(n-1)*(m-1)*2+1;
	inedge();
	for(int i=1;i<=nn;i++)d[i]=INF;
	SPFA();
	printf("%d\n",d[nn]);
	return 0;
}
